home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 22 / Cream of the Crop 22.iso / program / cgazv4n2.zip / SOUNDEX4.C < prev    next >
C/C++ Source or Header  |  1989-10-26  |  5KB  |  153 lines

  1. /************************** SOUNDEX4.C *************************
  2.  * Optimized Soundex Algorithm (Algorithm #4)
  3.  * Author: Joe Celko
  4.  * Compilers: Turbo C 2.0, Microsoft C 5.0
  5.  *
  6.  * Compile time switches:
  7.  *  TEST to get a test driver
  8.  *
  9.  * Source code may be freely used if source is acknowledged
  10.  * Object code may be freely used
  11.  */
  12.  
  13. /* Preserves first character, uppercase name, drop non-alphas
  14.  * convert letters to Soundex digits, and returns first n letters.
  15.  * Many of the steps here could be combined into the same loop,
  16.  * but they are kept separate for clarity and to give the user
  17.  * a chance to experiment with changes.
  18.  */
  19.  
  20. #define TEST 100
  21.  
  22. #include <string.h>
  23.  
  24. void soundex4 (char *inname,  /* name to be transformed */
  25.           char *outcode,      /* where to put soundex code */
  26.           int n               /* length of soundex code */
  27.          )
  28. {
  29.     char *p, *p1;
  30.     int i;
  31.     char workbuf[100];  /* that should be long enough */
  32.     char priorletter;   /* for duplicate checking */
  33.  
  34.     /* make a working copy */
  35.     strncpy(workbuf, inname, 99);
  36.     workbuf[99] = '\0'; /* just in case */
  37.     strupr(workbuf);
  38.  
  39.     /* convert all vowels to A */
  40.     for (p = workbuf; *p; p++)
  41.         if (strchr("AEIOUY", *p))
  42.             *p = 'A';
  43.  
  44.     /* prefix transformations: done only once on the front of a name */
  45.     if (strncmp(workbuf, "MAC", 3) == 0)      /* MAC to MCC */
  46.         workbuf[1] = 'C';
  47.     else if (strncmp(workbuf, "KN", 2) == 0)  /* KN to NN */
  48.         workbuf[0] = 'N';
  49.     else if (workbuf[0] == 'K')               /* K to C */
  50.         workbuf[0] = 'C';
  51.     else if (strncmp(workbuf, "PF", 2) == 0)  /* PF to FF */
  52.         workbuf[0] = 'F';
  53.     else if (strncmp(workbuf, "SCH", 3) == 0) /* SCH to SSS */ {
  54.         workbuf[1] = 'S';
  55.         workbuf[2] = 'S';
  56.     }
  57.  
  58.  
  59.     /* infix transformations: done after the first letter,
  60.      * and are from left to right on the name
  61.      */
  62.     while ((p = strstr(workbuf, "DG")) > workbuf)    /* DG to GG */
  63.         p[0] = 'G';
  64.     while ((p = strstr(workbuf, "CAAN")) > workbuf)  /* CANN to TAAN */
  65.         p[0] = 'T';
  66.     while ((p = strchr(workbuf, 'D')) > workbuf)    /* D to T */
  67.         p[0] = 'T';
  68.     while ((p = strstr(workbuf, "NST")) > workbuf)  /* NST to NTT */
  69.         p[2] = 'S';
  70.     while ((p = strstr(workbuf, "AV")) > workbuf)   /* AV to AF */
  71.         p[1] = 'F';
  72.     while ((p = strchr(workbuf, 'Q')) > workbuf)    /* Q to G */
  73.         p[0] = 'G';
  74.     while ((p = strchr(workbuf, 'Z')) > workbuf)    /* Z to S */
  75.         p[0] = 'S';
  76.     while ((p = strchr(workbuf, 'M')) > workbuf)    /* M to N */
  77.         p[0] = 'N';
  78.     while ((p = strstr(workbuf, "KN")) > workbuf)   /* KN to NN */
  79.         p[0] = 'N';
  80.     while ((p = strchr(workbuf, 'K')) > workbuf)    /* K to C */
  81.         p[0] = 'C';
  82.     while ((p = strstr(workbuf, "AH")) > workbuf)   /* AH to AA */
  83.         p[1] = 'A';
  84.     while ((p = strstr(workbuf, "HA")) > workbuf)   /* HA to AA */
  85.         p[0] = 'A';
  86.     while ((p = strstr(workbuf, "AW")) > workbuf)   /* AW to AA */
  87.         p[1] = 'A';
  88.     while ((p = strstr(workbuf, "PH")) > workbuf)   /* PH to FF */ {
  89.         p[0] = 'F';
  90.         p[1] = 'F';
  91.     }
  92.     while ((p = strstr(workbuf, "SCH")) > workbuf) {   /* SCH to SSS */
  93.         p[1] = 'S'; p[2] = 'S';
  94.     };
  95.  
  96.     /* suffix transformations: done on the end of the word,
  97.      * going right to left
  98.      */
  99.  
  100.     /* (1) remove terminal A's and S's */
  101.     i = strlen(workbuf) - 1;
  102.     for (; (i > 0) && (workbuf[i] == 'S' || workbuf[i] == 'A'); i--)
  103.         workbuf[i] = '\0';
  104.  
  105.     /* (2) terminal NT  to TT */
  106.     i = strlen(workbuf) - 1;
  107.     for (; (i > 0) && (workbuf[i-1] == 'N') && (workbuf[i] == 'T'); i--)
  108.         workbuf[i-1] = 'T';
  109.  
  110.     /* now strip out all vowels except the first (remember that all
  111.      * vowels were transformed into 'A's earlier).
  112.      */
  113.     p = p1 = workbuf;
  114.     while (*p1++ = *p++) {
  115.         while (*p == 'A')
  116.             p++;
  117.     }
  118.  
  119.     /* Remove all duplicate letters.
  120.      *  Note this is different from the Soundex3 (see article) duplicate
  121.      *  cleanup because the letter transforms can create duplicates
  122.      *  at the front of the output name.
  123.      */
  124.     p = p1 = workbuf;
  125.     priorletter = '\001'; /* an unlikely value */
  126.     do {
  127.         while (*p == priorletter)
  128.             p++;
  129.         priorletter = *p;
  130.     } while (*p1++ = *p++);
  131.  
  132.     strncpy(outcode, workbuf, n);
  133.     outcode[n] = '\0'; /* just in case */
  134. }
  135.  
  136. #if defined (TEST)
  137.  
  138. #include <stdio.h>
  139. #include <stdlib.h>
  140. void main(int argc, char **argv)
  141. {
  142.     char outbuf[50];
  143.  
  144.     if (argc != 3) {
  145.         puts("Usage: soundex4 name length\n");
  146.         exit(0);
  147.     }
  148.  
  149.     soundex4(argv[1], outbuf, atoi(argv[2]));
  150.  
  151.     printf(" Result: %s\n", outbuf);
  152. }
  153. #endif